package com.kingbook.core.scripting.nodes;


import com.kingbook.core.exception.SQLParserException;
import com.kingbook.common.utils.CollectionUtils;
import com.kingbook.common.utils.StringUtils;
import com.google.common.collect.Lists;
import org.jdom2.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.List;
import java.util.Map;

/**
 * @Author: Bucky
 * @Date: 2019/1/2
 * @Version 1.0
 */
public class WhenNode implements Node {

    private static Logger logger = LoggerFactory.getLogger(WhenNode.class);

    private String notNull = "";

    private String test = "";

    private List<Node> nodeList = Lists.newArrayList();

    WhenNode(Element element) {
        notNull = element.getAttributeValue("notNull");
        test = element.getAttributeValue("test");
        resolve(nodeList, element);
    }

    @Override
    public String getSql(Map<String, ?> paramMap, Map<String, SegmentNode> segMap) {
        if (notNullCheck(paramMap) && testCheck(paramMap))
            return getSql(nodeList, paramMap, segMap);
        else
            return "";
    }


    private boolean notNullCheck(Map<String, ?> paramMap) {
        if (StringUtils.isNotEmpty(notNull)) {
            String[] vs = getValiables(notNull, ",");
            for (String v : vs) {
                if (CollectionUtils.valueIsEmpty(paramMap, v)) {
                    return false;
                }
            }
        }
        return true;
    }

    private boolean testCheck(Map<String, ?> paramMap) {
        if (StringUtils.isEmpty(test))
            return true;
        try {
            ScriptEngineManager sem = new ScriptEngineManager();
            ScriptEngine engine = sem.getEngineByName("javascript");
            engine.eval("function condition(){ return (" + StringUtils.replaceAll(test, ":", "") + ") }");
//          logger.debug("[when] test=\"" + test + "\"");
            String[] valiabes = getValiables(test, "\\s+");
            for (String key : valiabes) {
                if (paramMap.containsKey(key))
                    engine.put(key, paramMap.get(key).toString());
                else
                    return false;
            }
            Invocable invocableEngine = (Invocable) engine;
            return (boolean) invocableEngine.invokeFunction("condition");
        } catch (ScriptException e) {
            throw new SQLParserException("[WhenNode] <when test=\"" + test + "\"> 该表达式判断错误，变量未定义。", e, logger);
        } catch (NoSuchMethodException e) {
            throw new SQLParserException("[WhenNode] <when test=\"" + test + "\"> 不支持该类型表达式，只能识别JavaScript表达式。", e, logger);
        }
    }

    private String[] getValiables(String str, String regex) {
        String[] s = str.split(regex);
        String sb = "";
        for (String tmp : s) {
            if (tmp.startsWith(":")) {
                sb += tmp.substring(1) + ",";
            }
        }
        return sb.split(",");
    }
}
